package com.woniuxy.broker.receiver;


import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;


/**
 * @author booty
 * @version 1.0
 * @date 2021/3/26 14:38
 */
@Slf4j
@Component
@RabbitListener(queues = "brokerQueryDelay1")
public class DelayReceiver {

    /**
     * 接收消息后手动确认的接收类
     * <p>
     * 收到消息后，使用message.getMessageProperties().getDeliveryTag()获取该消息的序号
     * 之后执行业务处理逻辑
     * 若处理正常，调用 channel.basicAck()方法，告知rabbitmq broker确认接收该消息
     * 若处理异常，调用 channel.basicReject()或channel。basicNack()方法，告知rabbitmq broker拒收该消息
     *
     * @param message         传递消息的协议
     * @param channel         频道
     * @param receivedMessage 收到的消息
     * @throws IOException 编译时异常
     */
    @RabbitHandler
    public void process(Message message, Channel channel, String receivedMessage) throws IOException {
        //获得投递序号
        long tag = message.getMessageProperties().getDeliveryTag();

        try {
            log.info("收到的消息为：" + receivedMessage);
            /*
             * 此处编写实际业务逻辑，在业务逻辑处理失败时手动（或框架自行，调用方法）抛出异常
             * 进入catch语句块，该条消息就不会被确认接收，若不做任何处理，
             * 下次启动会再次重新接收执行
             */
            log.info("模拟收到消息后的正常业务逻辑");

            /*
             * 业务逻辑处理完成后告知rabbitmq broker确认接收该消息，rabbitmq broker会将该消息从队列中删除
             * basicAck(long deliveryTag, boolean multiple)
             * 表示成功确认，使用此回执方法后，消息会被rabbitmq broker删除。
             * 参数：
             * long deliveryTag 消息序号
             * boolean multiple 是否批量确认
             */


            channel.basicAck(tag, false);
        } catch (Exception e) {
            /*
             * message.getMessageProperties().getRedelivered()
             * 判断该消息是否已经被接收过，若已经接收过则拒绝再次接收，否则将其重新加入接收队列
             *
             */
            if (message.getMessageProperties().getRedelivered()) {
                log.info("消息已重复处理失败,拒绝再次接收...");
                /*
                 * basicReject(long deliveryTag, boolean requeue)
                 * 拒绝消息，与basicNack区别在于不能进行批量操作，其他用法很相似。
                 * 参数：
                 * long deliveryTag 消息序号
                 * boolean requeue 是否将消息重新加入接收队列
                 */
                channel.basicReject(tag, false);
            } else {
                log.info("消息即将再次返回队列处理");
                /*
                 * basicNack(long deliveryTag, boolean multiple, boolean requeue)
                 * 表示失败确认，一般在消费消息业务异常时用到此方法，可以将消息重新投递入队列。
                 * 参数：
                 * long deliveryTag 消息序号
                 * boolean multiple 是否批量确认
                 * boolean requeue 是否将消息重新加入接收队列
                 */



                channel.basicNack(tag, false, true);
            }
        }
    }
}
